package qq2564874169.tuaotuao.fx.orm.execute;



import qq2564874169.tuaotuao.fx.FxAssert;
import qq2564874169.tuaotuao.fx.FxStream;
import qq2564874169.tuaotuao.fx.orm.DbEntity;
import qq2564874169.tuaotuao.fx.orm.ProcName;
import qq2564874169.tuaotuao.fx.orm.Sql;
import qq2564874169.tuaotuao.fx.orm.SqlParam;
import qq2564874169.tuaotuao.fx.orm.query.MysqlQuery;
import qq2564874169.tuaotuao.fx.orm.where.ExecuteWhere;
import qq2564874169.tuaotuao.fx.orm.where.MysqlWhere;
import qq2564874169.tuaotuao.fx.utils.StringUtil;

import java.util.Map;

public class MysqlExecute extends AbstractDbExecute {
    private Sql sql;

    public MysqlExecute(Sql sql) {
        super(sql, new MysqlQuery(sql));
        this.sql = sql;
    }

    private String getProcName(Object model) {
        ProcName annotation = model.getClass().getAnnotation(ProcName.class);
        return annotation == null ? model.getClass().getSimpleName() : annotation.value();
    }

    @Override
    protected SqlParam createInsert(SqlInsertContext context) {
        DbEntity entity = DbEntity.get(context.table);
        Map<String, Object> data = entity.getValues(context.model);
        String columns = "(" + String.join(",", FxStream.create(data.keySet()).map(i -> escapeField(i)).toArray(String.class)) + ")";
        String values = "(" + String.join(",", FxStream.create(data.keySet()).map(i -> paramName(i)).toArray(String.class)) + ")";
        SqlParam param = new SqlParam();
        param.command = "insert into " + escapeField(getTableName(context.table)) + columns + " values " + values;
        param.args.putAll(data);
        param.timeout = context.timeout;
        return param;
    }

    @Override
    protected String getIncSql(String column) {
        return "SELECT LAST_INSERT_ID()";
    }

    @Override
    protected SqlParam createUpdate(SqlUpdateContext context) {
        DbEntity entity = DbEntity.get(context.setTable);
        Map<String, Object> setPs = entity.getValues(context.set);
        FxAssert.isNotEquals(0, setPs.size(), "Update没有任何更新");
        SqlParam param = new MysqlWhere(sql).parse(context.where);
        String sets;
        if (context.isSetNull) {
            sets = FxStream.create(setPs.keySet()).map(i -> escapeField(i) + "=NULL").strjoin(",");
        } else {
            sets = FxStream.create(setPs.keySet()).map(i -> {
                String pn = "set_" + i;
                param.args.put(pn, setPs.get(i));
                return escapeField(i) + "=" + paramName(pn);
            }).strjoin(",");
        }
        String sql = "update " + escapeField(getTableName(context.setTable));
        if (StringUtil.hasValue(context.where.index())) {
            sql += " force index(" + this.sql.escapeField(context.where.index()) + ")";
        }
        param.command = sql + " set " + sets + param.command;
        param.timeout = context.timeout;
        return param;
    }

    @Override
    protected SqlParam createDelete(ExecuteWhere<?> where, Integer timeout) {
        DbEntity entity = DbEntity.get(where.getTable());
        SqlParam param = new MysqlWhere(sql).parse(where);
        String sql = "delete from " + escapeField(getTableName(where.getTable()));
        if (StringUtil.hasValue(where.index())) {
            sql += " force index(" + this.sql.escapeField(where.index()) + ")";
        }
        param.command = sql + param.command;
        param.timeout = timeout;
        return param;
    }

    @Override
    protected SqlParam createProc(Object model, Integer timeout) {
        DbEntity entity = DbEntity.get(model.getClass());
        SqlParam param = new SqlParam();
        param.command = getProcName(model);
        param.args.putAll(entity.getValues(model));
        param.timeout = timeout;
        param.isProc = true;
        return param;
    }
}
